#include <stdio.h>
#include <sys/types.h>          
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>

typedef struct Data{
    int code;
    char name[32];
    char data[500];
}MSG;

typedef struct UserDatalist{
    MSG UserData; 
    struct sockaddr_in useraddr;
    struct UserDatalist *next;
}USERMESS;

USERMESS * link_creat(void)
{
	USERMESS *H = (USERMESS *)malloc(sizeof(USERMESS));
	if(NULL==H){
		printf("creat list error\n");
		return NULL;
	}
	H->next = NULL;
	return H;
}

int link_head_insert(USERMESS *H,MSG uservalue,struct sockaddr_in data)
//int link_head_insert(USERMESS *H,MSG uservalue)
{
	
	if(NULL==H){
		printf("传入的表参数非法\n");
		return -1;
	}

	USERMESS *p = (USERMESS *)malloc(sizeof(USERMESS));
	if(NULL==p){
		printf("申请新数据节点失败\n");
		return -1;
	}
    strcpy(p->UserData.name,uservalue.name);
    p->useraddr=data;

	p->next = H->next;
	H->next = p;

	return 0;
}


typedef struct pipelist{
    struct sockaddr_in everuseraddr;
    struct pipelist *next;
}pipec;

pipec * linksys_creat(void)
{
	pipec *H = (pipec *)malloc(sizeof(pipe));
	if(NULL==H){
		printf("creat list error\n");
		return NULL;
	}
	H->next = NULL;
	return H;
}

int linksys_head_insert(pipec *H,struct sockaddr_in data)
{
	if(NULL==H){
		printf("传入的表参数非法\n");
		return -1;
	}

	pipec *p = (pipec *)malloc(sizeof(pipe));
	if(NULL==p){
		printf("申请新数据节点失败\n");
		return -1;
	}
    p->everuseraddr=data;

	p->next = H->next;
	H->next = p;

	return 0;
}

int main(int argc, char const *argv[])
{

    int fd[2];
    if(-1==pipe(fd))
    {
        perror("pipe");
        return -1;
    }
    char welcome[50]="welcome----------";
    char goodbye[50]="goodbye----------";
    char sendmessage[600]={0};
    struct sockaddr_in seraddr,cliaddr,desaddr;
    MSG syssendmessage;
    USERMESS usermessage;
    USERMESS *H;
    USERMESS *q;
   
    pipec *h;
    pipec *p;

	int sockfd;
	socklen_t addrlen=sizeof(cliaddr);
	
	if(-1==(sockfd=socket(AF_INET,SOCK_DGRAM,0)))
	{
		perror("socket");
		return -1;
	}


	seraddr.sin_family=AF_INET;
	seraddr.sin_addr.s_addr=inet_addr(argv[1]);
	seraddr.sin_port=htons(atoi(argv[2]));
	
	if(bind(sockfd,(struct sockaddr *)&seraddr,addrlen) == -1)
	{
		perror("bind");
		return -1;
	}

    pid_t pid=fork();
    if(pid==0)
    {
/*        
        pipec *h=linksys_creat();
        close(fd[1]);
        read(fd[0],&desaddr,sizeof(desaddr));
        linksys_head_insert(h,desaddr);
        while(1)
        {
            
            char sysmess[512]={0};
            char sysmessage[600]={0};
            strcpy(sysmessage,"***system***:");
            fgets(sysmess,512,stdin);
            sysmess[strlen(sysmess)-1]='\0';
            strcpy(sysmessage+13,sysmess);

            p = h->next;
            while(p!=NULL)
            {
                if(-1==sendto(sockfd,sysmess,sizeof(sysmess),0,(struct sockaddr *)&(p->everuseraddr),addrlen))
                {
                    perror("send sys");
                    return -1;
                }
                p=p->next;
            }
            memset(sysmess,0,512);
        }
*/
        while(1)
        {
            fgets(syssendmessage.data,sizeof(syssendmessage.data),stdin);
            syssendmessage.data[strlen(syssendmessage.data)-1]='\0';
            syssendmessage.code=2;
            strcpy(syssendmessage.name,"**systemwarning**");
            sendto(sockfd,&syssendmessage,sizeof(syssendmessage),0,(struct sockaddr *)&seraddr,addrlen);
        }
    }
    else if(pid>0)
    {
//        close(fd[0]);
        USERMESS *H=link_creat();
        MSG datas;
        while(1)
        {
            if(-1==(recvfrom(sockfd,&datas,sizeof(datas),0,(struct sockaddr *)&cliaddr,&addrlen)))
            {
                perror("recv datapackage");
                return -1;
            }
            
            if(datas.code==1) 
            {

                link_head_insert(H,datas,cliaddr);
 //               write(fd[1],&cliaddr,sizeof(cliaddr));
                printf("%s %d %s is online\n",inet_ntoa(cliaddr.sin_addr),ntohs(cliaddr.sin_port),datas.name);
                
                strcpy(welcome+17,datas.name);
                q = H->next;
                while(q!=NULL)
                {
                    if(-1==(sendto(sockfd,welcome,sizeof(welcome),0,(struct sockaddr *)&(q->useraddr),addrlen)))
                    {
                        perror("send welcome");
                        return -1;
                    }
                    q=q->next;
                }
            }
            if(datas.code==2)
            {
                sprintf(sendmessage,"%s:%s",datas.name,datas.data);

                printf("%s\n",sendmessage);
                q = H->next;
                while(q!=NULL)
                {
                
                    if(-1==(sendto(sockfd,sendmessage,sizeof(sendmessage),0,(struct sockaddr *)&(q->useraddr),addrlen)))
                    {
                        perror("send message");
                        return -1;
                    }
                    q=q->next;
                }

            }
            if(datas.code==3)
            {
                printf("%s %d %s is offline\n",inet_ntoa(cliaddr.sin_addr),ntohs(cliaddr.sin_port),datas.name);
                strcpy(goodbye+17,datas.name);
                q = H->next;
                while(q!=NULL)
                {
                    if(-1==(sendto(sockfd,goodbye,sizeof(goodbye),0,(struct sockaddr *)&(q->useraddr),addrlen)))
                    {
                        perror("send goodbye");
                        return -1;
                    }
                    q=q->next;
                }
            }
        }      
    }
    return 0;
}
